package com.wqnmdb.im.utils;


import lombok.AccessLevel;
import lombok.AllArgsConstructor;

import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;


/**
 * 对称加密算法 PBE
 */
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class PBEUtil {

    /**
     * 支持以下任意一种算法
     * PBEWithMD5AndDES
     * PBEWithMD5AndTripeDES
     * PBEWithSHA1AndDESede
     * PBEWITHSHA1ANDRC2_40
     * PBKDF2WITHHMACSHA1
     */
    public static final String ALGORITHM = "PBEWITHMD5andDES";

    /**
     * 迭代次数
     */
    public static final int ITERATION_COUNT = 100;


    /**
     * 加密  cmd 1-加密  2-解密
     *
     * @param data     待加密数据
     * @param password 密码
     * @param s        盐
     * @return byte[] 加密数据
     */
    private static byte[] start(byte[] data, String password, String s, int cmd) throws Exception {
        byte[] salt = Base64.getDecoder().decode(s);
        //密钥转换
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
        //生成密钥
        Key key = keyFactory.generateSecret(keySpec);

        //实例化PBE参数材料
        PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);
        //实例化
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        //初始化
        if (cmd == 1) {
            cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
        }
        //执行操作
        return cipher.doFinal(data);
    }

    /**
     * 盐初始化
     * 盐长度必须为8字节
     */
    public static String initSalt() {
        //实例化安全随机数
        SecureRandom random = new SecureRandom();
        //产出盐
        byte[] bytes = random.generateSeed(8);
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * 加密  cmd 1-加密  2-解密
     * cmd == 1 时，data为需要加密的数据
     * cmd == 2 时，data为加密后的串
     */
    public static String encryptAndDecrypt(String data, String password, String salt, int cmd) {
        String result = "";
        try {
            if (cmd == 1) {
                byte[] encrypt = new byte[0];
                encrypt = start(data.getBytes(), password, salt, cmd);
                result = Base64.getEncoder().encodeToString(encrypt);
            } else if (cmd == 2) {
                byte[] decrypt = start(Base64.getDecoder().decode(data), password, salt, cmd);
                result = new String(decrypt);
            } else {
                result = "";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            return result;
        }
    }

    /**
     * 使用PBE算法对数据进行加解密
     *
     * @throws Exception
     */
/*    public static void main(String[] args) throws Exception {
        //待加密数据
        String str = "TEST";
        //设定的口令密码
        String password = "azsxdc";
        System.out.println("原文：" + str);
        System.out.println("密码：" + password);
        //初始化盐
        String salt = PBEUtil.initSalt();
        System.out.println("盐：" + salt);

        String e = encryptAndDecrypt(str, password, salt, 1);
        System.out.println("加密后：" + e);
        System.out.println("解密后：" + encryptAndDecrypt(e, password, salt, 2));
    }*/
}